import React, { useEffect, useMemo, useState } from "react";
import { Skeleton, SkeletonProps } from "antd";
import { utils } from "elmer-common";
import { IServiceApi, useService } from "../../Service/Provider";
import { useIntl } from "react-intl";

type IWithLoadingDisplayMode = "Skeleton"| "Other";

export interface IWithLoadingApi {
    visible: boolean;
    show: () => void;
    hide: () => void;
    serviceApi: IServiceApi;
    // intl: IntlShape
}

export interface IWithLoadingOption {
    defaultVisible?: boolean;
    mode?: IWithLoadingDisplayMode;
    loadingComponent?: React.ComponentType<any>;
    skeletonProps?: SkeletonProps;
    mountWithLoading?: boolean;
    controlled?: boolean;
    onMounted?: (api: IWithLoadingApi) => void;
    onUnmount?: Function;
    onResponse?: <T={}, Err ={}>(data: { positive: boolean, data?: T, error?: Err, withLoadingApi: IWithLoadingApi}) => any;
    goto?: () => void;
}

export type ITargetComponentProps<TargetComponentProps={}, ResponseData={}> = TargetComponentProps & {
    withLoadingApi: IWithLoadingApi;
    responseData: ResponseData;
}

export const withLoading = (option?: IWithLoadingOption) => <T={}, ResponseData={}>(TargetComponent: React.ComponentType<ITargetComponentProps<T, ResponseData>>): React.ComponentType<T> => {
    const antdSkeletonProps = option?.skeletonProps || {
        active: true,
        paragraph: {
            rows: 8
        }
    };
    return (props) => {
        const [ displayMode ] = useState<IWithLoadingDisplayMode>(option?.mode ?? "Skeleton");
        const [ showLoading, setShowLoading ] = useState(option?.defaultVisible ?? false);
        const [ updateNextProps, setUpdateNextProps ] = useState<any>();
        const [ tempState ] = useState({
            mounted: false
        })
        const serviceApi = useService();
        const intl = useIntl();
       
        const withLoadingApi = useMemo(() => ({
            visible: showLoading,
            data: updateNextProps,
            show: () => setShowLoading(true),
            hide: () => {
                setShowLoading(false);
            },
            serviceApi,
            // intl,
            goto: () => {
                console.log("----App--");
            }
        }), [showLoading, updateNextProps, serviceApi]);
        const childrenStyle = useMemo(() => {
            return {
                display: showLoading ? "none" : "block"
            };
        }, [showLoading]);
        useEffect(() => {
            if(typeof option?.onMounted === "function" && withLoadingApi.serviceApi && !tempState.mounted){
                tempState.mounted = true;
                utils.invoke(option.onMounted, withLoadingApi).then((data) => {
                    const nextData = typeof option?.onResponse === "function" ? option?.onResponse({
                        positive: true,
                        data,
                        withLoadingApi
                    }) : data;
                    setUpdateNextProps(nextData);
                }).catch((err) => {
                    console.error(err);
                    const errResponse = typeof option?.onResponse === "function" && option?.onResponse({
                        positive: false,
                        error: err,
                        withLoadingApi
                    });
                    console.error(errResponse);
                    setUpdateNextProps(errResponse);
                });
            }
            return () => typeof option?.onUnmount === "function" && option?.onUnmount(withLoadingApi);
        }, [withLoadingApi]);
        
        return (<>
            {
                !option?.mountWithLoading && displayMode === "Skeleton" && (<Skeleton loading={showLoading} paragraph {...antdSkeletonProps}>
                    <TargetComponent {...props} responseData={updateNextProps} withLoadingApi={withLoadingApi}/>
                </Skeleton>)
            }
            {
                option?.mountWithLoading && (<section>
                    <div style={childrenStyle}>
                        <TargetComponent {...props} responseData={updateNextProps} withLoadingApi={withLoadingApi}/>
                    </div>
                    { displayMode === "Skeleton" && <Skeleton loading={showLoading} paragraph {...antdSkeletonProps}></Skeleton> }
                </section>)
            }
        </>);
    };
}
